package files;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * @date 29.5.2011
 */
public class FileHandler {
	
	private RandomAccessFile file;
	
	private RandomAccessFile getFile() {
		return this.file;
	}
	
	private void setFile(RandomAccessFile file) {
		this.file = file;
	}
	
	/**
	 * Constructor
	 * @param filename The file to be opened
	 * @throws FileNotFoundException If the given file was not found.
	 * This should not ever be thrown, because of the file mode "rw"
	 * (the file is created if it does not already exist)
	 */
	public FileHandler(String filename) throws FileNotFoundException {
		this.setFile(new RandomAccessFile(filename, "rw"));
	}
	
	/**
	 * Reads the given amount of bytes from the opened file
	 * @param bytes The amount of bytes to be read
	 * @return The read bytes or null if the end of file was already reached
	 * @throws IOException If any IO errors occur
	 */
	public byte[] read(int bytes) throws IOException {
		byte[] data = new byte[bytes];
		int bytesRead = this.getFile().read(data, 0, bytes);
		if (bytesRead == -1) {
			return null;
		} else {
			if (bytesRead < bytes) {
				/**
				 * Remove the unused part of the array
				 */
				byte[] temp = new byte[bytesRead];
				System.arraycopy(
					data, 0, // source
					temp, 0, // destination
					bytesRead); // copy length
				return temp;
			}
			return data;
		}
	}
	
	/**
	 * Reads the given amount of bytes starting from the given position
	 * from the opened file
	 * @param bytes The number of bytes to be read
	 * @param position The starting position of the reading operation
	 * @return The read bytes or null if the end of the file was already reached
	 * @throws IOException If any IO errors occur
	 */
	public byte[] readFrom(int bytes, long position) throws IOException {
		byte[] data = new byte[bytes];
		/**
		 * Save the current position of the file pointer
		 */
		long currentPosition = this.getFile().getFilePointer();
		/**
		 * Move the pointer to the wanted position
		 * and read the data
		 */
		this.getFile().seek(position);
		int bytesRead = this.getFile().read(data, 0, bytes);
		/**
		 * Move the pointer back to the original position
		 */
		this.getFile().seek(currentPosition);
		if (bytesRead == -1) {
			return null;
		} else {
			if (bytesRead < bytes) {
				/**
				 * Remove the unused part of the array
				 */
				byte[] temp = new byte[bytesRead];
				System.arraycopy(
					data, 0, // source
					temp, 0, // destination
					bytesRead); // copy length
				return temp;
			}
			return data;
		}
	}
	
	/**
	 * Writes the given data to the file
	 * @param data The data to be written to the file
	 * @throws IOException If any IO errors occur
	 */
	public void write(byte[] data) throws IOException {
		this.getFile().write(data);
	}
	
	/**
	 * Writes the given data to the given position in the file
	 * @param data The data to be written
	 * @param position The position where the writing is started
	 * @throws IOException If any IO errors occur
	 */
	public void write(byte[] data, long position) throws IOException {
		/**
		 * Save the current position of the file pointer
		 */
		long currentPosition = this.getFile().getFilePointer();
		/**
		 * Write the given data to the wanted position
		 * and return the file pointer to its original position
		 */
		this.getFile().seek(position);
		this.getFile().write(data);
		this.getFile().seek(currentPosition);
	}
	
	/**
	 * Closes the current file
	 * @throws IOException If any I/O errors occur
	 */
	public void close() throws IOException {
		if (this.getFile() != null) {
			this.getFile().close();
		}
	}
	
	/**
	 * Checks does a file with the given name exist
	 * @param filename The file to be checked
	 * @return True if the file exists, false otherwise
	 */
	public static boolean exists(String filename) {
		File f = new File(filename);
		boolean exists = f.exists();
		f = null;
		return exists;
	}
	
	/**
	 * Gets size of the given file
	 * @param filename The file to be checked
	 * @return The size of the file
	 */
	public static long getFilesize(String filename) {
		File f = new File(filename);
		if (f.exists()) {
			return f.length();
		} else {
			return 0;
		}
	}
}